﻿using System.Threading;
using Fetches.Fetch.Dto;

namespace Fetches.Fetch.PagePool
{
    /// <summary>
    /// 页面本地存储
    /// 虽然这个步骤导致比其他爬虫多了一步获取到的页面的存盘读盘过程，但是对于爬取的分布式爬取的解耦很有用
    /// </summary>
    public abstract class AbstractPagePool
    {
        public int MaxOffset;
        /// <summary>
        /// PagePool停止写入后消费结束判断才有意义
        /// 默认PagePool视为只读状态，爬虫操作时变为写入状态，爬取结束重新设为只读状态
        /// </summary>
        public bool ReadOnly = true;

        #region 接口方法

        /// <summary>
        /// 
        /// </summary>
        /// <param name="config"></param>
        /// <param name="uniqueId"></param>
        public virtual void Initialize(string config, long uniqueId)
        {
        }

        /// <summary>
        /// 先填充Page需要计算的信息，然后实际写入Page，由Supervisor来通知消费页面
        /// </summary>
        /// <param name="responsePage"></param>
        /// <returns>返回缓存的页面ID,一般忽略</returns>
        public string Cache(ResponsePage responsePage)
        {
            responsePage.Calc();
            Store(responsePage);
            Interlocked.Increment(ref MaxOffset);
            return responsePage.Id;
        }

        public virtual bool IsEnd(int offset)
        {
            if (ReadOnly)
            {
                return offset >= MaxOffset;
            }
            return false;
        }
        #endregion

        #region PagePool内部的方法
        /// <summary>
        /// 根据ID取Page数据,ID会在Cache时发布到队列,消费队列就有ID
        /// </summary>
        /// <param name="pageId"></param>
        /// <returns></returns>
        public abstract ResponsePage Get(string pageId);
        /// <summary>
        /// 用于遍历数据
        /// </summary>
        /// <param name="offset"></param>
        /// <returns></returns>
        public abstract ResponsePage Get(int offset);
        /// <summary>
        /// 用于配合Coordinator，省的Page多次传递
        /// </summary>
        /// <param name="offset"></param>
        /// <returns>返回Offset自身代表该Offset有效
        /// 返回-1代表该Offset暂时无效请等待重试
        /// 返回大于Offset的数字表示该Offset已删除，有效Offset为返回的数字</returns>
        public abstract int ValidateOffset(int offset);
        /// <summary>
        /// 实际存储动作
        /// </summary>
        /// <param name="responsePage"></param>
        protected abstract void Store(ResponsePage responsePage);
        #endregion

    }
}